//
//  Primer_ErrorHandling_DemoVC.swift
//  APSwift
//
//  Created by jianbo.pei on 2022/10/14.
//

import UIKit

enum SomeError: Error {
    /// 错误参数
    case illegalArg(String)
    /// 越界（数组）
    case outOfBounds(Int, Int)
    /// 内存溢出
    case outOfMemory
}

class Primer_ErrorHandling_DemoVC: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
//        test1()
        
//        test2()
        
//        test3()
        
//        test4()
        
        test5()
    }

}

extension Primer_ErrorHandling_DemoVC {

    func divide2(_ num1: Int, _ num2: Int) throws -> Int {
        if num2 == 0 {
            throw SomeError.illegalArg("0不能作为除数")
        }
        return num1 / num2
    }
    
    /// 除法
    func divide1(_ num1: Int, _ num2: Int) -> Int {
        num1 / num2
    }
}

extension Primer_ErrorHandling_DemoVC {
    enum MyError: Error {
        case invalidValue
    }

    
    func test5() {
        let numbers = ["1", "2", "three", "4"]
        
        let numbers1 = numbers.map({ Int($0)} )
        
        let numbers2 = numbers.map { str in
            if let number = Int(str) {
                return number
            } else {
                return 0
            }
        }

        debugPrint("numbers1 is \(numbers1)")
        debugPrint("numbers2 is \(numbers2)")

        do {
            let convertedNumbers = try numbers.map { value in
                if let number = Int(value) {
                    return number
                } else {
                    throw MyError.invalidValue
                }
            }
            print(convertedNumbers)
        } catch {
            print("Error occurred: \(error)")
        }
        
        let convertedNumbers1 = try? numbers.map { value in
            if let number = Int(value) {
                return number
            } else {
                throw MyError.invalidValue
            }
        }
        print("convertedNumbers1 is: \(String(describing: convertedNumbers1))")
        
        let convertedNumbers2 = try! numbers.map { value in
            if let number = Int(value) {
                return number
            } else {
                throw MyError.invalidValue
            }
        }
        print("convertedNumbers2 is: \(String(describing: convertedNumbers2))")
    }
}


extension Primer_ErrorHandling_DemoVC {
    
    //MARK: `try?`和 `try!` 处理错误
    /// ①：可以使用 try? 通过将错误转换成一个可选值来处理错误。如果是在计算 try? 表达式时抛出错误，该表达式的结果就为 nil。
    /// ②：在表达式前面写 try! 来禁用错误传递，这会把调用包装在一个不会有错误抛出的运行时断言中。
    ///    如果真的抛出了错误，你会得到一个运行时错误。
    func test4() {
        let r1 = try? divide2(20, 10)
        let r2 = try? divide2(20, 0)
        debugPrint("r1 is \(String(describing: r1))")
        debugPrint("r2 is \(String(describing: r2))")
        
        debugPrint(try! divide2(20, 10))
        debugPrint(try! divide2(20, 0))
        
        /**
         "r1 is Optional(2)"
         "r2 is nil"
         2
         APSwift/Primer_ErrorHandling_DemoVC.swift:63: Fatal error: 'try!' expression unexpectedly raised an error: APSwift.SomeError.illegalArg("0不能作为除数")
         */
    }
    
    //MARK: `do-catch`处理异常
    func test3() {
        debugPrint("11")
        do {
            debugPrint("22")
            debugPrint(try divide2(20, 0))
            debugPrint("33")
        } catch SomeError.illegalArg(let errMsg) {
            debugPrint("44 参数异常：\(errMsg)")
        } catch let SomeError.outOfBounds(start, total) {
            debugPrint("55 数组越界：\(start) - \(total)")
        } catch SomeError.outOfMemory {
            debugPrint("66 内存溢出")
        } catch {
            debugPrint("77 未知错误")
        }
    }
    
    //MARK: 抛出异常，但未处理
    func test2() {
//        debugPrint(try divide2(20, 0))
        /// Errors thrown from here are not handled
        /**
         上面代码抛出的异常提示信息时我们自定义的，但是依然报错了，
         是因为我们只是让编译器能够抛出异常，我们并没有处理异常，程序运行过程中依旧会崩溃。
         要想程序正常运行，就需要捕获并处理异常。
         */
    }
    
    func test1() {
        /// ✔️ 2
        print(divide1(20, 10))
        /// ❎ 崩溃：Fatal error: Division by zero
        print(divide1(20, 0))
    }
}

extension Primer_ErrorHandling_DemoVC {
    private func test() {
        let vm = VendingMachine()
        try? vm.vend(itemNamed: "Chips")
        try? vm.vend(itemNamed: "AbnerPei")
    }
}
